package com.furyspring.factory;

import com.furyspring.annotation.Autowired;
import com.furyspring.annotation.Service;
import com.furyspring.annotation.Transactional;
import com.furyspring.utils.StringUtils;
import org.reflections.Reflections;

import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @author Spring Wang
 * @date 2021/6/6
 */
public class AnnotatedBeanResolver {

    private static final Map<String, Object> map = new HashMap<>();
    private static final String SCAN_PACKAGE = "com.furyspring.service";


    public static Map<String, Object> initAnnotationBeans() {
        try {
            // 扫描包，实例化bean
            registerAnnotationBeans();
            // Autowired属性依赖注入
            bindAutowired();
            // aop切面增强，维护事务
            handleProxyBeans();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    private static void registerAnnotationBeans() throws Exception {
        Reflections reflections = new Reflections(SCAN_PACKAGE);
        // 获取带有Service注解类型的类
        Set<Class<?>> annotatedClasses = reflections.getTypesAnnotatedWith(Service.class);
        for (Class<?> aClass : annotatedClasses) {
            // 通过反射技术实例化对象
            Object beanObject = aClass.getConstructor().newInstance();
            // 获取注解信息
            Service annotation = aClass.getAnnotation(Service.class);
            // 该实例service注解有value时用value的值，没有时用类名
            if (StringUtils.isEmpty(annotation.value())) {
                // 由于getName获取的是全限定类名，所以要分割去掉包名部分
                Class<?>[] interfaces = aClass.getInterfaces();
                for (Class<?> interfaceClass : interfaces) {
                    String[] names = interfaceClass.getName().split("\\.");
                    map.put(StringUtils.lowerFirstCase(names[names.length - 1]), beanObject);
                }
            } else {
                map.put(annotation.value(), beanObject);
            }
        }
    }

    private static void bindAutowired() throws Exception {
        // 实例化对象后，开始维护对象的依赖关系Autowired，检查哪些对象需要传值注入
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object bean = entry.getValue();
            Class<?> beanClass = bean.getClass();
            // 获取所有变量
            Field[] declaredFields = beanClass.getDeclaredFields();
            // 遍历变量，如果持有Autowired注解则注入
            for (Field field : declaredFields) {
                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
                // 获取变量的类型名(这里基本等于获取类名)
                String[] names = field.getType().getName().split("\\.");
                Object object = BeanFactory.getBean(StringUtils.lowerFirstCase(names[names.length - 1]));
                field.setAccessible(true);
                // 赋值
                field.set(bean, object);
            }
        }
    }

    private static void handleProxyBeans() {
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object bean = entry.getValue(); //获取bean
            Class<?> beanClass = bean.getClass();
            // 判断对象类是否有Transactional注解，如果有则修改对象为代理对象
            if (beanClass.isAnnotationPresent(Transactional.class)) {
                // 获取代理工厂
                ProxyFactory proxyFactory = (ProxyFactory) BeanFactory.getBean("proxyFactory");
                bean = proxyFactory.getProxy(bean);
                // 把处理好的bean重新放入map中
                map.put(entry.getKey(), bean);
            }
        }
    }
}
